#include "update_value_task.h"
#include "qmsd_board_utils.h"
#include "qmsd_utils.h"

#include "time_utils.h"

#include "ui_event_manager.h"
#include "temperature_reader.h"
#include "gpio_pwm_out.h"
#include "data_shared.h"

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "esp_system.h"
#include "esp_log.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <math.h>
#include <time.h>
#include "qmsd_utils.h"
#include "esp_err.h"
#include "esp_sleep.h"

#include "pid_grando.h"
#include "pid_autotune.h"
#include "pid_pmeasure.h"
#define TAG "Update-task"
#define OUT_PIN 10
static uint32_t _output = 0;
static float _foutput = 0;
static float _input = 0;
static pid_cache_t pid_cache = {0};

pid_autotune_t *pid_autotune_ptr = NULL;
pid_pmeasure_ctrl_t *pid_pm_ctrl_ptr = NULL;
    ///初始化面板时间以及IO引脚输出
    static void
    init_service()
{
    ESP_LOGI(TAG, "gpio output init");
    set_currment_time(2024, 1, 1, 0, 0, 0);
    gpio_out_config(OUT_PIN);
    gpio_set_state(OUT_PIN, false);
}
static void sync_output()
{
    if (_foutput <= 0)
    {
        _output = 0;
    }
    else
    {
        _output = _foutput;
    }
}
static void output_pwm(int all_ms, uint32_t out_ms)
{

    uint32_t cur_time = qmsd_get_time_ms();
    ESP_LOGI(TAG, "time: %u,pv:%.2f,sv:%.2f,output:%u", cur_time, _input, pid_cache.sv, _output);
    // 控制IO输出高电平
    gpio_set_state(OUT_PIN, true);
    vTaskDelay(pdMS_TO_TICKS(out_ms));
    // 控制IO输出低电平
    gpio_set_state(OUT_PIN, false);
    vTaskDelay(pdMS_TO_TICKS(all_ms - out_ms));
}
/// @brief 初始化自整定
static void init_autotune_configure()
{
    if (pid_autotune_ptr != NULL)
        return;
    ESP_LOGI(TAG, "autotune configure init");
    _foutput = 500;
    pid_autotune_ptr = pid_autotune_create(&_input, &_foutput);
    pat_set_output_step(pid_autotune_ptr, 500);
}
/// @brief 自整定执行
static void run_autotune()
{
    init_autotune_configure();
    ESP_LOGI(TAG, "autotune running");
    int ret = pat_runtime(pid_autotune_ptr);

    if (AUTOTUNE_FINISHED == ret)
    {

        ui_set_autotune(false);
        db_set_autotune_state(false);

        pid_cache.kp = pat_get_kp(pid_autotune_ptr);
        pid_cache.ki = pat_get_ki(pid_autotune_ptr);
        pid_cache.kd = pat_get_kd(pid_autotune_ptr);

        db_set_pid_cache(&pid_cache);

        ui_update_all_data();

        pid_autotune_free(pid_autotune_ptr);
        pid_autotune_ptr = NULL;
    }
    else
    {
        sync_output();
        output_pwm(pid_cache.out_time_ms, _output);
        //vTaskDelay(pdMS_TO_TICKS(500));
    }
}

static void init_pid_configure()
{
    if (pid_pm_ctrl_ptr != NULL)
        return;
    ESP_LOGI(TAG, "pid configure init ");
    db_get_pid_cache(&pid_cache);
    pid_pm_ctrl_ptr = pid_pmeasure_ctrl_new(&_input, &_foutput, &(pid_cache.sv), pid_cache.kp,
                                            pid_cache.ki,
                                            pid_cache.kd,
                                            P_ON_M, DIRECT);
    pid_pmeasure_ctrl_set_output_limits(pid_pm_ctrl_ptr, pid_cache.out_min, pid_cache.out_max);
}
/// @brief 计算输出
/// @param input
/// @return
static void cal_out(float input)
{
    bool ret = pid_pmeasure_ctrl_compute(pid_pm_ctrl_ptr);
    if (ret)
    {
        sync_output();
    }
}
static void run_ctrl_temp()
{
    /// 获取pid参数
    init_pid_configure();

    // 计算
    cal_out(_input);

    // 存储输出
    db_set_output(_output);

    output_pwm(pid_cache.out_time_ms, _output);
}

/// @brief 初始化更新pid任务
/// @param pvParameters
void init_update_pid_task(void *pvParameters)
{

    ESP_LOGI(TAG, "updating pid task");
    init_service();
    vTaskDelay(pdMS_TO_TICKS(2000));

    uint32_t cur_time = 0;
    while (1)
    {
        // 执行自整定
        if (db_get_autotune_state())
        {
            run_autotune();
        }
        // 执行控温
        else
        {
            run_ctrl_temp();
        }
    }
}
/// @brief 更新温度线程
/// @param pvParameters
void init_runtime_read_temperature(void *pvParameters)
{
    ESP_LOGI(TAG, "updating pid task");
    temp_ctrl_uart_init();
    while (1)
    {
        // 读取温度
        temp_ctrl_read(&_input);
        // 存储温度
        db_add_data(_input);

        vTaskDelay(pdMS_TO_TICKS(300));
    }
}
/// @brief 初始化更新ui任务
/// @param pvParameters
void init_update_ui_task(void *pvParameters)
{

    ESP_LOGI(TAG, "updating ui task");
    while (1)
    {

        // 更新ui 数据显示
        ui_update_all_data();
        // 更新led 开启状态
        ui_update_led(true);
        vTaskDelay(pdMS_TO_TICKS(_output));
        // 更新led 关闭状态
        ui_update_led(false);
        vTaskDelay(pdMS_TO_TICKS(pid_cache.out_time_ms - _output));

        vTaskDelay(pdMS_TO_TICKS(500));
    }
}
